home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume3 / can2 < prev    next >
Encoding:
Internet Message Format  |  1989-02-03  |  25.7 KB

  1. Path: xanth!mcnc!gatech!mandrill!hal!ncoast!allbery
  2. From: athey@cod.nosc.mil (The Bit Butcher)
  3. Newsgroups: comp.sources.misc
  4. Subject: v03i075: "can" a fast "C" version, a great alias for "rm"
  5. Message-ID: <8807072011.AA08841@cod.nosc.mil>
  6. Date: 7 Jul 88 20:11:06 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: athey@cod.nosc.mil (The Bit Butcher)
  9. Lines: 884
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. Posting-number: Volume 3, Issue 75
  13. Submitted-by: "The Bit Butcher" <athey@cod.nosc.mil>
  14. Archive-name: can2
  15.  
  16.     This is a "C" version of an earlier posting of mine.  It is a
  17. great alias for "rm".  It moves the file to your personal trashcan.
  18. If you are consistently bothered by users or are a user yourself
  19. who is bothered by you own ineptitude in removal of files you
  20. realize you really don't want gone then this is just the thing for
  21. you.  Enjoy.
  22.  
  23.     Yes, I know that this is amazingly similiar to the "rmunrm"
  24. package that can be found at simtel20, but I just thought that since
  25. mine is pretty fast and has some nice options, at least as far
  26. as I am concerned.  One thing that the other package does that I
  27. don't is preserve directories.  In other words, if you "can" two
  28. files with the same name you will only have the last one you "can"ned.
  29.  
  30.             -the bit butcher
  31.  
  32. mail me:   athey@nosc.mil
  33.  
  34. #! /bin/sh
  35. # This is a shell archive.  Remove anything before this line, then unpack
  36. # it by saving it into a file and typing "sh file".  To overwrite existing
  37. # files, type "sh file -c".  You can also feed this as standard input via
  38. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  39. # will see the following message at the end:
  40. #        "End of shell archive."
  41. # Contents:  ReadMe Makefile.BSD Makefile.SUN Makefile.SYSV can.1 can.c
  42. #   can.h emptytrash emptytrash.8 recurcan.c xdevcan.c
  43. # Wrapped by athey@unicorn on Thu Jul  7 10:35:01 1988
  44. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  45. if test -f 'ReadMe' -a "${1}" != "-c" ; then 
  46.   echo shar: Will not clobber existing file \"'ReadMe'\"
  47. else
  48. echo shar: Extracting \"'ReadMe'\" \(2456 characters\)
  49. sed "s/^X//" >'ReadMe' <<'END_OF_FILE'
  50. XWell, I am back again and you may not be rejoicing.
  51. X
  52. XThis is CAN 2.0.
  53. XYes it is all (almost all) new.
  54. X
  55. XFirst, what you need to do to make this nifty thing for yourself
  56. Xor your system (if you are the system manager)
  57. X
  58. X1.  Copy the appropriate Makefile to Makefile and then compile.
  59. X2.  Edit emptytrash to make it look in the trashcans of your system.
  60. X3.  Install all of this wonderful stuff (Don't forget the man pages).
  61. X    Make sure to make "emptytrash" executable by the crontab that will run it.
  62. X
  63. XSecond, So why have you wasted my time again or why version 2.0?
  64. X
  65. X1.  Well, I rewrote the entire can in C.  This made it move twice as fast.
  66. X    Still a little slower than rm but certainly much nicer.
  67. X2.  In the process of rewriting it, I added the verbose option and the 
  68. X    interactive option.
  69. X
  70. XThird, There are some things about this that you should know.
  71. X
  72. X1.  This is my first attempt at a "C" utility but as far as I can tell,
  73. X    it does the trick.
  74. X2.  It only changes the access time, not the modification time and then
  75. X    empties trash on the basis of access time.  So, if you are really
  76. X    hard-core, you can see if the one you removed and then recovered is
  77. X    really the version you want.
  78. X3.  This has the same handicap as my original script.  You can only recover
  79. X    one file at a time, and you must know it's specific name.  If I have
  80. X    time I will try my best to fix this problem.
  81. X4.  The listing option is very primitive but since it traverses the
  82. X    directory tree by where it is placed, the last things canned are
  83. X    usually at the end of the list.  I, once again, will do what I can
  84. X    to repair these features (bugs?).
  85. X5.  This is my first time passing around multiple system designs.
  86. X    If I have a poor conception of what any system is like please let
  87. X    me know at the address below. (rhyme?)
  88. X6.  You may have the possibility of a pathname greater than 80.  I rarely do.
  89. X    To remedy any problems caused by this, simply change the define
  90. X    entitled MAXPATHLEN.
  91. X7.  May be possible to add a force option, but I don't see the necessity
  92. X    of it right now.
  93. X
  94. XIf you have any complaints or you have bug fixes or
  95. Xanything of the sort please write me at
  96. X
  97. X            "athey@nosc.mil"
  98. X
  99. XPlease write me if you install this and find it useful.
  100. XJust a quick note would be great, everybody.
  101. XI mean let me know if I should keep posting this artwork (junk?).
  102. X        -the bit butcher
  103. X
  104. XNOTE: CAN 2.01  now we can deal with cross device canning.
  105. XNOTE: CAN 2.02  segmented and cleaned code.
  106. END_OF_FILE
  107. if test 2456 -ne `wc -c <'ReadMe'`; then
  108.     echo shar: \"'ReadMe'\" unpacked with wrong size!
  109. fi
  110. # end of 'ReadMe'
  111. fi
  112. if test -f 'Makefile.BSD' -a "${1}" != "-c" ; then 
  113.   echo shar: Will not clobber existing file \"'Makefile.BSD'\"
  114. else
  115. echo shar: Extracting \"'Makefile.BSD'\" \(307 characters\)
  116. sed "s/^X//" >'Makefile.BSD' <<'END_OF_FILE'
  117. XCFLAGS        = -O -DBSD
  118. X
  119. XDEST          = /cd441/athey/bin
  120. X
  121. XLIBS          =
  122. X
  123. XLINKER          = cc
  124. X
  125. XMAKEFILE      = Makefile
  126. X
  127. XOBJS          = can.o recurcan.c xdevcan.c
  128. X
  129. XPROGRAM          = can
  130. X
  131. XSRCS          = can.c
  132. X
  133. Xall:        $(PROGRAM)
  134. X
  135. X$(PROGRAM):     $(OBJS) 
  136. X        $(LINKER) $(OBJS) $(LIBS) -o $(PROGRAM)
  137. X
  138. Xclean:;        rm -f $(OBJS)
  139. END_OF_FILE
  140. if test 307 -ne `wc -c <'Makefile.BSD'`; then
  141.     echo shar: \"'Makefile.BSD'\" unpacked with wrong size!
  142. fi
  143. # end of 'Makefile.BSD'
  144. fi
  145. if test -f 'Makefile.SUN' -a "${1}" != "-c" ; then 
  146.   echo shar: Will not clobber existing file \"'Makefile.SUN'\"
  147. else
  148. echo shar: Extracting \"'Makefile.SUN'\" \(307 characters\)
  149. sed "s/^X//" >'Makefile.SUN' <<'END_OF_FILE'
  150. XCFLAGS        = -O -DSUN
  151. X
  152. XDEST          = /cd441/athey/bin
  153. X
  154. XLIBS          =
  155. X
  156. XLINKER          = cc
  157. X
  158. XMAKEFILE      = Makefile
  159. X
  160. XOBJS          = can.o recurcan.c xdevcan.c
  161. X
  162. XPROGRAM          = can
  163. X
  164. XSRCS          = can.c
  165. X
  166. Xall:        $(PROGRAM)
  167. X
  168. X$(PROGRAM):     $(OBJS) 
  169. X        $(LINKER) $(OBJS) $(LIBS) -o $(PROGRAM)
  170. X
  171. Xclean:;        rm -f $(OBJS)
  172. END_OF_FILE
  173. if test 307 -ne `wc -c <'Makefile.SUN'`; then
  174.     echo shar: \"'Makefile.SUN'\" unpacked with wrong size!
  175. fi
  176. # end of 'Makefile.SUN'
  177. fi
  178. if test -f 'Makefile.SYSV' -a "${1}" != "-c" ; then 
  179.   echo shar: Will not clobber existing file \"'Makefile.SYSV'\"
  180. else
  181. echo shar: Extracting \"'Makefile.SYSV'\" \(327 characters\)
  182. sed "s/^X//" >'Makefile.SYSV' <<'END_OF_FILE'
  183. XCFLAGS        = -O -DSYSV
  184. X
  185. XDEST          = /cd441/athey/bin
  186. X
  187. XLIBS          = -lndir -ljobs
  188. X
  189. XLINKER          = cc
  190. X
  191. XMAKEFILE      = Makefile
  192. X
  193. XOBJS          = can.o recurcan.o xdevcan.o
  194. X
  195. XPROGRAM          = can
  196. X
  197. XSRCS          = can.c
  198. X
  199. Xall:        $(PROGRAM)
  200. X
  201. X$(PROGRAM):     $(OBJS) can.h
  202. X        $(LINKER) $(OBJS) $(LIBS) -o $(PROGRAM)
  203. X
  204. Xclean:;        rm -f $(OBJS)
  205. END_OF_FILE
  206. if test 327 -ne `wc -c <'Makefile.SYSV'`; then
  207.     echo shar: \"'Makefile.SYSV'\" unpacked with wrong size!
  208. fi
  209. # end of 'Makefile.SYSV'
  210. fi
  211. if test -f 'can.1' -a "${1}" != "-c" ; then 
  212.   echo shar: Will not clobber existing file \"'can.1'\"
  213. else
  214. echo shar: Extracting \"'can.1'\" \(1788 characters\)
  215. sed "s/^X//" >'can.1' <<'END_OF_FILE'
  216. X.\" @(#)run.1    10.2 (MASSCOMP) 8/14/86
  217. X.RL "local"
  218. X.TH CAN 1
  219. X.SH NAME
  220. Xcan \- a replacement for rm that is safe
  221. X.SH SYNOPSIS
  222. X\fB can [ ivlrR ] <file | directory> ...
  223. X.br
  224. X.ns
  225. X.SH DESCRIPTION
  226. X.I Can
  227. Xis often an alias of
  228. X.I rm(1).
  229. X.I Can
  230. Xworks similiarly, with the exception of putting things into a directory, in
  231. Xyour home directory, called ".trashcan."
  232. XThe
  233. X.B -i
  234. Xoption makes it interactive, querying for each "can"-ing.
  235. XThe 
  236. X.B -v
  237. Xoption gives a verbose following of all activities of this command.
  238. XThe
  239. X.B -l
  240. Xoption will give you a listing of the "$HOME/.trashcan"
  241. Xdirectory.
  242. XThe
  243. X.B -r
  244. Xoption works recursively just the same as 
  245. X.I rm(1).
  246. X.sp
  247. XThe 
  248. X.B -R
  249. Xoption will retrieve a file from the "$HOME/.trashcan" without the hassle
  250. Xof looking for it.  The
  251. X.B -R
  252. Xoption copies the file from the "$HOME/.trashcan" directory into the
  253. Xpresent working directory.  This can only recover one file at a time and
  254. Xis the only option that requires an argument.  You should
  255. Xnote that
  256. X.B -R
  257. Xwill destroy the file in the working directory if it has the same name
  258. Xas the file that is being recovered, so use with caution.
  259. XYou cannot use 
  260. X.B -r
  261. Xand
  262. X.B -R
  263. Xin the same command and the file to be recoved must not have a directory
  264. Xname in it.
  265. X.sp
  266. XThe trash gets dumped everyday but only gets rid of things that
  267. Xare more than a week old.  In other words, you have a week to get something
  268. Xback after you have
  269. X.I can
  270. Xned it.
  271. X.SH FILES
  272. X.TP 2.5i
  273. X$HOME/.trashcan
  274. XThe reservoir of canned files
  275. X.SH SEE ALSO
  276. X.I
  277. Xemptytrash(8), rm(1)
  278. X.SH BUGS
  279. XThe 
  280. X.B -R
  281. Xoption does not work on wild cards.  You have to know the
  282. Xexact name of a file in order to recover it with this command.
  283. X.sp
  284. XIf further bugs are found please report them.
  285. X.SH AUTHOR
  286. XThe Bit Butcher
  287. X.br
  288. XInspired by the original
  289. X.B can
  290. Xwhich was written by a Russ Sage.
  291. END_OF_FILE
  292. echo shar: 1 control character may be missing from \"'can.1'\"
  293. if test 1788 -ne `wc -c <'can.1'`; then
  294.     echo shar: \"'can.1'\" unpacked with wrong size!
  295. fi
  296. # end of 'can.1'
  297. fi
  298. if test -f 'can.c' -a "${1}" != "-c" ; then 
  299.   echo shar: Will not clobber existing file \"'can.c'\"
  300. else
  301. echo shar: Extracting \"'can.c'\" \(6932 characters\)
  302. sed "s/^X//" >'can.c' <<'END_OF_FILE'
  303. X/*************************************************************
  304. X*    can.c    2.0
  305. X*
  306. X*    This is a utility to replace rm.  I hope you like it
  307. X*
  308. X*    written by "the bit butcher"
  309. X*
  310. X*    2.02 changed the error handling to cases and segmented the
  311. X*         program into three pieces and now have "can.h"
  312. X*            28 June 1988
  313. X*
  314. X*    2.01 changed the way cross device problems are dealt with
  315. X*        copy file from one system to the other
  316. X*            before 28 June 1988
  317. X*************************************************************/
  318. X
  319. X#include "can.h"
  320. X
  321. Xchar CAN[MAXPATHLEN];    /* String containing .trashcan directory*/    
  322. Xchar ANSWER[14];        /* String used for finding interactive response */
  323. Xint VERBOSE = 0;            /* Set if Verbose is wanted */
  324. Xint INTERACTIVE = 0;            /* Set if Interactive is wanted */
  325. Xlong TIME;        /* Used to get the current time */
  326. XUTIMBUF TIMES;    /* Structure used to change the access time */
  327. X
  328. Xmain(argc, argv)
  329. Xint argc;
  330. Xchar** argv;
  331. X{
  332. X    int c;                        /* which character in getopt */
  333. X    DIR *DIRP;        /* Used to list the directory by pointing at .trashcan */
  334. X    struct direct *DP;    /* Used to point at consecutive entries when listing */
  335. X    char FILENAME[MAXPATHLEN];    /* String containing .trashcan/current file*/    
  336. X    char *ACTNAME;        /* Points to filename without any leading directory */
  337. X    struct stat BUF;    /* Used to point to mode info about files */
  338. X    int RECURSIVE = 0;            /* Set if Recursive is wanted */
  339. X#ifdef SYSV
  340. X    int UID;    /* Variable holding user's ID */
  341. X#endif
  342. X#ifdef SUN
  343. X    int UID;    /* Variable holding user's ID */
  344. X#endif
  345. X#ifdef BSD
  346. X    uid_t UID;    /* Variable holding user's ID */
  347. X#endif
  348. X    char TEMP[MAXPATHLEN];    /* Used for quick access of file names */
  349. X    struct passwd *USERINFO;    /* Structure used to find out $HOME dir */
  350. X    extern int optind;    /* used to step through arguments */
  351. X    extern char *optarg;    /* used to step through arguments */
  352. X    int    errflag = 0;    /* Used to indicate errors in options */
  353. X    void recurcan();    /* Say this is a void function */
  354. X
  355. X    /* Find out the users ID */
  356. X    if((UID= getuid()) == NULL)
  357. X    {
  358. X        fprintf(stderr, "Invalid Login: Who Are You!?!\n");
  359. X        exit(0);
  360. X    }
  361. X
  362. X    /* Get his home directory from the passwd file */
  363. X    USERINFO = getpwuid(UID);
  364. X    if(USERINFO->pw_dir == NULL)
  365. X    {
  366. X        fprintf(stderr, "No Home Directory: check /etc/passwd !!!\n");
  367. X        exit(0);
  368. X    }
  369. X    /*  say where the trashcan will be */
  370. X    sprintf(CAN, "%s/.trashcan", USERINFO->pw_dir);
  371. X
  372. X    /* make sure there is a trashcan */
  373. X    if (access(CAN, F_OK) != 0)
  374. X        /* if not, make a trashcan */
  375. X        if(mkdir(CAN, 004777) != 0)
  376. X        {
  377. X            perror("can");
  378. X            exit(2);
  379. X        }
  380. X
  381. X    /* could add force (-f) option later, perhaps */
  382. X    /* Let's look at the options */
  383. X    while((c=getopt(argc, argv, "ivlR:r")) != EOF)
  384. X        switch(c)
  385. X        {
  386. X            case 'l':    /* list the contents by stepping through */
  387. X                fprintf(stdout, "%s\n", CAN);
  388. X                DIRP = opendir(CAN);
  389. X        /* Could allow arguments for selective listing */
  390. X                for(DP = readdir(DIRP); DP != NULL; DP= readdir(DIRP))
  391. X                    fprintf(stdout, "%s\n", DP->d_name);
  392. X                closedir(DIRP);
  393. X                exit(0);
  394. X                break;
  395. X            case 'v':    /* Set the verbose mode */
  396. X                VERBOSE++;
  397. X                break;
  398. X            case 'i':    /* Set the interactive mode */
  399. X                INTERACTIVE++;
  400. X                break;
  401. X            case 'R':    /* Recover a file */
  402. X                if(RECURSIVE)    /* if recursive point out illegal option 
  403. X                                combination */
  404. X                {
  405. X                    errflag++;
  406. X                    break;
  407. X                }
  408. X                /* get name of file to recover */
  409. X                strcpy(TEMP, optarg);
  410. X                /* does it have a directory in its name ? (it should not) */
  411. X                if((ACTNAME = strrchr(TEMP, '/')) != NULL)
  412. X                {
  413. X                    fprintf(stderr, "can: cannot access %s\n", TEMP);
  414. X                    fprintf(stderr, "    no directory names in Recovery\n");
  415. X                    continue;
  416. X                }
  417. X                else
  418. X                    /* name the actual file in the trashcan to get */
  419. X                    sprintf(FILENAME, "%s/%s", CAN, TEMP);
  420. X                /* does it exist in the trashcan */
  421. X                if(access(FILENAME, F_OK) != 0)
  422. X                {
  423. X                    fprintf(stderr, "can: %s does not exist\n", TEMP);
  424. X                    continue;
  425. X                }
  426. X                /* interogate just in case */
  427. X                if (INTERACTIVE)
  428. X                {
  429. X                    fprintf(stdout, "can recover: %s\? ", TEMP);
  430. X                    fscanf(stdin, "%s", ANSWER);
  431. X                    if ((ANSWER[0] != 'y') && (ANSWER[0] != 'Y'))
  432. X                        continue;
  433. X                }
  434. X                /* get rid of file if it exists in current directory */
  435. X                if (access(TEMP, F_OK) == 0)
  436. X                    if (unlink(TEMP) != 0)
  437. X                    {
  438. X                        perror("can");
  439. X                        continue;
  440. X                    }
  441. X                /* get a new copy of the file into the working directory */
  442. X                if (link(FILENAME, TEMP) != 0)
  443. X                {
  444. X                    perror("can");
  445. X                    continue;
  446. X                }
  447. X                /* say it has been recycled */
  448. X                fprintf(stdout, "%s: recovered\n", TEMP);
  449. X                exit(0);
  450. X                break;
  451. X            case 'r':    /* Let's get recursive */
  452. X                RECURSIVE++;
  453. X                break;
  454. X            default:    /* Errors in bad options */
  455. X                errflag++;
  456. X                break;
  457. X        }
  458. X
  459. X        /* say if there are some bad options */
  460. X        if(errflag)
  461. X        {
  462. X            fprintf(stderr, "%s\n", USAGE);
  463. X            exit(2);
  464. X        }
  465. X
  466. X        /* get the current time */
  467. X        if((TIME =time(0)) == 0)
  468. X        {
  469. X            perror("can");
  470. X            exit(2);
  471. X        }
  472. X        /* step through the arguments to see what to get rid of */
  473. X        for( ; optind < argc; optind++)
  474. X        {
  475. X            strcpy(TEMP, argv[optind]);    /* get the next argument */
  476. X            stat(TEMP, &BUF);    /* get file info about this file */
  477. X            /* Check for the existence of a file that is not a directory */
  478. X            if ((access(TEMP, F_OK) == 0) && (!(BUF.st_mode & 0040000)))
  479. X            {
  480. X                /* interogate */
  481. X                if(INTERACTIVE != 0)
  482. X                {
  483. X                    fprintf(stdout, "can %s\? ", TEMP);
  484. X                    fscanf(stdin, "%s", ANSWER);
  485. X                    if((ANSWER[0] != 'y') && (ANSWER[0] != 'Y'))
  486. X                        continue;
  487. X                }
  488. X                /* strip off directory names so we can trash it properly */
  489. X                if((ACTNAME = strrchr(TEMP, '/')) != NULL)
  490. X                    sprintf(FILENAME, "%s%s", CAN, ACTNAME);
  491. X                else
  492. X                    sprintf(FILENAME, "%s/%s", CAN, TEMP);
  493. X                /* if it exists in the trashcan already get rid of it */
  494. X                if (access(FILENAME, F_OK) == 0)
  495. X                    if(unlink(FILENAME) != 0)
  496. X                    {
  497. X                        perror("can3");
  498. X                        continue;
  499. X                    }
  500. X                /* put it in the trashcan */
  501. X                if(link(TEMP, FILENAME) != 0)
  502. X                {
  503. X                    switch(errno)
  504. X                    {
  505. X                        case EXDEV:
  506. X                            crossdevcan(TEMP, FILENAME);
  507. X                            break;
  508. X                        default:
  509. X                            perror("can1");
  510. X                            continue;
  511. X                    }
  512. X                }
  513. X                /* get rid of the original */
  514. X                if(unlink(TEMP) != 0)
  515. X                {
  516. X                    perror("can4");
  517. X                    continue;
  518. X                }
  519. X                /* change the access time */
  520. X                TIMES.actime= (time_t)TIME;
  521. X                TIMES.modtime= BUF.st_mtime;
  522. X                if(utime(FILENAME, &TIMES) != 0)
  523. X                {
  524. X                    perror("can5");
  525. X                    continue;
  526. X                }
  527. X                /* tell them what we did if they want to know */
  528. X                if(VERBOSE)
  529. X                    fprintf(stdout, "%s: canned\n", TEMP);
  530. X            }
  531. X            else
  532. X            {
  533. X                /* is this a directory? */
  534. X                if(BUF.st_mode & 0040000)
  535. X                {
  536. X                    if(RECURSIVE == 0) /* yes, then do recursion if OK */
  537. X                        fprintf(stderr, "cannot can: %s directory\n", TEMP);
  538. X                    else
  539. X                    {
  540. X                        if(INTERACTIVE != 0)
  541. X                        {
  542. X                            fprintf(stdout, "can check %s directory\? ", TEMP);
  543. X                            fscanf(stdin, "%s", ANSWER);
  544. X                            if((ANSWER[0] != 'y') && (ANSWER[0] != 'Y'))
  545. X                                continue;
  546. X                        }
  547. X                        recurcan(TEMP);
  548. X                    }
  549. X                }
  550. X                else    /* the file does not exist */
  551. X                    perror("can6");
  552. X            }
  553. X        }
  554. X}
  555. END_OF_FILE
  556. if test 6932 -ne `wc -c <'can.c'`; then
  557.     echo shar: \"'can.c'\" unpacked with wrong size!
  558. fi
  559. # end of 'can.c'
  560. fi
  561. if test -f 'can.h' -a "${1}" != "-c" ; then 
  562.   echo shar: Will not clobber existing file \"'can.h'\"
  563. else
  564. echo shar: Extracting \"'can.h'\" \(1096 characters\)
  565. sed "s/^X//" >'can.h' <<'END_OF_FILE'
  566. X/******************************************************************
  567. X*
  568. X*    CAN.H
  569. X*
  570. X*
  571. X*
  572. X******************************************************************/
  573. X
  574. X#include <stdio.h>
  575. X#include <pwd.h>
  576. X#include <string.h>
  577. X#include <errno.h>
  578. X#include <fcntl.h>
  579. X#include <sys/types.h>
  580. X#include <sys/timeb.h>
  581. X#include <sys/file.h>
  582. X#include <sys/stat.h>
  583. X
  584. X#ifdef SYSV
  585. X#include <ndir.h>
  586. X#endif
  587. X
  588. X#ifdef SUN
  589. X#include <sys/dir.h>
  590. X#endif
  591. X
  592. X#ifdef BSD
  593. X#include <sys/dir.h>
  594. X#endif
  595. X
  596. X#define USAGE "usage: can [ivlrR] file ..."
  597. X#define MAXPATHLEN 80    /* Longest possible path name */
  598. X
  599. Xextern char CAN[];    /* String containing .trashcan directory*/    
  600. Xextern char ANSWER[];        /* String used for finding interactive response */
  601. Xextern int VERBOSE;            /* Set if Verbose is wanted */
  602. Xextern int INTERACTIVE;            /* Set if Interactive is wanted */
  603. Xextern long TIME;        /* Used to get the current time */
  604. Xextern int errno;    /* Used to return the error value */
  605. Xtypedef struct utimbuf
  606. X{
  607. X    time_t actime;    /* access time */
  608. X    time_t modtime;    /* modification time */
  609. X} UTIMBUF;    /* Structure used to change the access time */
  610. Xextern UTIMBUF TIMES;
  611. END_OF_FILE
  612. if test 1096 -ne `wc -c <'can.h'`; then
  613.     echo shar: \"'can.h'\" unpacked with wrong size!
  614. fi
  615. # end of 'can.h'
  616. fi
  617. if test -f 'emptytrash' -a "${1}" != "-c" ; then 
  618.   echo shar: Will not clobber existing file \"'emptytrash'\"
  619. else
  620. echo shar: Extracting \"'emptytrash'\" \(472 characters\)
  621. sed "s/^X//" >'emptytrash' <<'END_OF_FILE'
  622. X: /bin/sh
  623. X
  624. X# EMPTYTRASH 
  625. X# Executed from root crontab file every night.
  626. X# It finds all files in all users .traschan directories and gets
  627. X# rid of any file that has not been accessed or modified for more
  628. X# than 7 days.  Note:  this works in conjunction with can.  can
  629. X# changes modifies the access time for a file when it moves the  
  630. X# file to the user's .trashcan diretory.
  631. X
  632. Xfind /cd441/*/.trashcan -atime +7 -print | while read FILE
  633. Xdo 
  634. X#       echo $FILE
  635. X    rm $FILE
  636. Xdone
  637. END_OF_FILE
  638. if test 472 -ne `wc -c <'emptytrash'`; then
  639.     echo shar: \"'emptytrash'\" unpacked with wrong size!
  640. fi
  641. # end of 'emptytrash'
  642. fi
  643. if test -f 'emptytrash.8' -a "${1}" != "-c" ; then 
  644.   echo shar: Will not clobber existing file \"'emptytrash.8'\"
  645. else
  646. echo shar: Extracting \"'emptytrash.8'\" \(871 characters\)
  647. sed "s/^X//" >'emptytrash.8' <<'END_OF_FILE'
  648. X.\" @(#)run.1    10.2 (MASSCOMP) 8/14/86
  649. X.RL "local"
  650. X.TH EMPTYTRASH 8
  651. X.SH NAME
  652. Xemptytrash \- the trash collector used with
  653. X.I can
  654. X.SH SYNOPSIS
  655. X\fBemptytrash
  656. X.br
  657. X.ns
  658. X.SH DESCRIPTION
  659. X.I Emptytrash
  660. Xsimply looks into each $HOME/.trashcan and checks the last access time
  661. Xwhich is usually set by
  662. X.I can(1).
  663. XAnything that it finds that is more than seven days old it permanently
  664. Xremoves via 
  665. X.I rm(1).
  666. XThis amount of time can be changed by changing the "7" in the script file.
  667. XThe best thing to do is to put this in your root crontab file and have it
  668. Xexecuted everyday.
  669. X.SH FILES
  670. X.TP 2.5i
  671. X$HOME/.trashcan
  672. XThe reservoir of canned files
  673. X.SH SEE ALSO
  674. X.I
  675. Xcan(1), rm(1)
  676. X.SH BUGS
  677. XOnly that this was a quicky and could be made better by having it accept an
  678. Xargument that would determine the amount of elapsed time to check for.
  679. X.SH AUTHOR
  680. XThe Bit Butcher
  681. X.br
  682. XWith the help of Steph Luse.
  683. END_OF_FILE
  684. if test 871 -ne `wc -c <'emptytrash.8'`; then
  685.     echo shar: \"'emptytrash.8'\" unpacked with wrong size!
  686. fi
  687. # end of 'emptytrash.8'
  688. fi
  689. if test -f 'recurcan.c' -a "${1}" != "-c" ; then 
  690.   echo shar: Will not clobber existing file \"'recurcan.c'\"
  691. else
  692. echo shar: Extracting \"'recurcan.c'\" \(3460 characters\)
  693. sed "s/^X//" >'recurcan.c' <<'END_OF_FILE'
  694. X/************************************************************************
  695. X*
  696. X*    RECURCAN.C
  697. X*        this is used to traverse a directory tree when doing a
  698. X*        recursive can passed the directory to be examined
  699. X*
  700. X************************************************************************/
  701. X
  702. X#include "can.h"
  703. X
  704. Xvoid recurcan(temp)
  705. Xchar *temp;
  706. X{
  707. X    DIR *DIRP;        /* Used to list the directory by pointing at .trashcan */
  708. X    struct direct *DP;    /* Used to point at consecutive entries when listing */
  709. X    char FILENAME[MAXPATHLEN];    /* String containing .trashcan/current file*/    
  710. X    char *ACTNAME;        /* Points to filename without any leading directory */
  711. X    struct stat BUF;    /* Used to point to mode info about files */
  712. X    char TEMP[MAXPATHLEN];    /* this is used to look at the current file */
  713. X    char WORKDIR[MAXPATHLEN];    /* the working directory we came from */
  714. X
  715. X    DIRP = opendir(temp);    /* open the directory being canned */
  716. X    getwd(WORKDIR);    /* get the current working directory */
  717. X    chdir(temp);    /* go to the directory to be canned */
  718. X    /* get the next directory entry */
  719. X    for(DP = readdir(DIRP); DP != NULL; DP= readdir(DIRP))
  720. X    {
  721. X        strcpy(TEMP, DP->d_name);    /* put the name in TEMP */
  722. X        stat(TEMP, &BUF);    /* get some info about this file */
  723. X        /* does it exist and is it not a directory */
  724. X        if ((access(TEMP, F_OK) == 0) && (!(BUF.st_mode & 0040000)))
  725. X        {
  726. X            /* interogate */
  727. X            if(INTERACTIVE != 0)
  728. X            {
  729. X                fprintf(stdout, "can %s\? ", TEMP);
  730. X                fscanf(stdin, "%s", ANSWER);
  731. X                if((ANSWER[0] != 'y') && (ANSWER[0] != 'Y'))
  732. X                    continue;
  733. X            }
  734. X            /* make the name of the trash file */
  735. X            sprintf(FILENAME, "%s/%s", CAN, TEMP);
  736. X            /* get rid of the trash version if there is one */
  737. X            if (access(FILENAME, F_OK) == 0)
  738. X                if(unlink(FILENAME) != 0)
  739. X                {
  740. X                    perror("can7");
  741. X                    continue;
  742. X                }
  743. X            /* put file in the trash */
  744. X            if(link(TEMP, FILENAME) != 0)
  745. X            {
  746. X                switch(errno)
  747. X                {
  748. X                    case EXDEV:
  749. X                        crossdevcan(TEMP, FILENAME);
  750. X                        break;
  751. X                    default:
  752. X                        perror("can2");
  753. X                        continue;
  754. X                }
  755. X            }
  756. X            /* get rid of the file here */
  757. X            if(unlink(TEMP) != 0)
  758. X            {
  759. X                perror("can8");
  760. X                continue;
  761. X            }
  762. X            /* change the access time */
  763. X            TIMES.actime= (time_t)TIME;
  764. X            TIMES.modtime= BUF.st_mtime;
  765. X            if(utime(FILENAME, &TIMES) != 0)
  766. X            {
  767. X                perror("can9");
  768. X                continue;
  769. X            }
  770. X            /* tell them what happened if they want to know */
  771. X            if(VERBOSE)
  772. X                fprintf(stdout, "%s: canned\n", TEMP);
  773. X        }
  774. X        else
  775. X        {
  776. X            /* is it a directory? */
  777. X            if(BUF.st_mode & 0040000)
  778. X            {
  779. X                /* make sure it is not ".." or "." */
  780. X                if((strcmp(TEMP,"..") != 0) && (strcmp(TEMP,".") != 0))
  781. X                {
  782. X                    /* make sure they want to look at this directory */
  783. X                    if(INTERACTIVE != 0)
  784. X                    {
  785. X                        fprintf(stdout, "can check %s directory\? ", TEMP);
  786. X                        fscanf(stdin, "%s", ANSWER);
  787. X                        if((ANSWER[0] != 'y') && (ANSWER[0] != 'Y'))
  788. X                            continue;
  789. X                    }
  790. X                    /* get on with recursion using newest directory */
  791. X                    recurcan(TEMP);
  792. X                }
  793. X            }
  794. X            else
  795. X                perror("can10");
  796. X        }
  797. X    }
  798. X    chdir(WORKDIR);    /* go back to directory from which started */
  799. X    closedir(DIRP);    /* close the one we were canning */
  800. X    /* make sure they want to get rid of the directory */
  801. X    if(INTERACTIVE != 0)
  802. X    {
  803. X        fprintf(stdout, "can directory %s\? ", temp);
  804. X        fscanf(stdin, "%s", ANSWER);
  805. X        if((ANSWER[0] != 'y') && (ANSWER[0] != 'Y'))
  806. X            return;
  807. X    }
  808. X    /* get rid of the directory */
  809. X    if(rmdir(temp) != 0)
  810. X        perror("can11");
  811. X    else
  812. X        /* tell them if they want to know */
  813. X        if(VERBOSE)
  814. X            fprintf(stdout, "%s: canned directory\n", temp);
  815. X}
  816. END_OF_FILE
  817. if test 3460 -ne `wc -c <'recurcan.c'`; then
  818.     echo shar: \"'recurcan.c'\" unpacked with wrong size!
  819. fi
  820. # end of 'recurcan.c'
  821. fi
  822. if test -f 'xdevcan.c' -a "${1}" != "-c" ; then 
  823.   echo shar: Will not clobber existing file \"'xdevcan.c'\"
  824. else
  825. echo shar: Extracting \"'xdevcan.c'\" \(1664 characters\)
  826. sed "s/^X//" >'xdevcan.c' <<'END_OF_FILE'
  827. X/***********************************************************************
  828. X*
  829. X*    XDEVCAN.C
  830. X*        this is called and the file is copied via read and write to 
  831. X*        the other device, sure it may be slow but it solves a problem 
  832. X*        of cross device links crossdevcan(OLDFILE, NEWFILE)
  833. X*
  834. X***********************************************************************/
  835. X
  836. X#include "can.h"
  837. X
  838. Xcrossdevcan(OLDFILE, NEWFILE)
  839. Xchar *OLDFILE, *NEWFILE;
  840. X{
  841. X    int oldFD, newFD;    /* File Descriptors for access */
  842. X    char NEXTCHAR[512];    /* used to transfer the char to new place */
  843. X    int RWSIZE = 512;    /* amount to read and write */
  844. X    struct stat BUF;    /* used to transfer all stats of old file to new */
  845. X    int n_read;    /* the number of bytes successfully read */
  846. X
  847. X    /* create the new file in the trashcan */
  848. X    if((newFD = creat(NEWFILE, 00777)) < 0)
  849. X    {
  850. X        perror("Cross Device can");
  851. X        return;
  852. X    }
  853. X    /* open the old one to be read */
  854. X    if((oldFD = open(OLDFILE, O_RDONLY)) < 0)
  855. X    {
  856. X        perror("Cross Device can");
  857. X        return;
  858. X    }
  859. X    /* repeatedly read and write until whole file is copied */
  860. X    while((n_read = read(oldFD, NEXTCHAR, RWSIZE)) != 0)
  861. X    {
  862. X        if((write(newFD, NEXTCHAR, n_read)) != n_read)
  863. X        {
  864. X            perror("Cross Device can");
  865. X            return;
  866. X        }
  867. X    }
  868. X    /* close the files */
  869. X    close(oldFD);
  870. X    close(newFD);
  871. X    /* get info concerning the old file */
  872. X    stat(OLDFILE, &BUF);
  873. X    /* make the new file's modes the same as the old one's */
  874. X    if(chmod(NEWFILE, (int)(BUF.st_mode & 0777)) != 0)
  875. X    {
  876. X        perror("Cross Device can");
  877. X        return;
  878. X    }
  879. X    /* make the new file's times the same as the old one's */
  880. X    TIMES.actime= BUF.st_atime;
  881. X    TIMES.modtime= BUF.st_mtime;
  882. X    if(utime(NEWFILE, &TIMES) != 0)
  883. X    {
  884. X        perror("Cross Device can");
  885. X        return;
  886. X    }
  887. X}
  888. END_OF_FILE
  889. if test 1664 -ne `wc -c <'xdevcan.c'`; then
  890.     echo shar: \"'xdevcan.c'\" unpacked with wrong size!
  891. fi
  892. # end of 'xdevcan.c'
  893. fi
  894. echo shar: End of shell archive.
  895. exit 0
  896.